
#ifndef RTCHANNELHTTPCLIENT_H
#define RTCHANNELHTTPCLIENT_H

#include "RtReferenceControl.h"
#include "RtChannelHttpBase.h"
#include "RtHttpHeadParser.h"
#include "RtHttpAuthenticator.h"
#include "RtObserver.h"

class /*RT_API_EXPORT*/ CRtChannelHttpClient
	: public IRtChannelHttpClient
	, public CRtChannelHttpBase
	, public CRtReferenceControlSingleThreadTimerDelete
	, public IRtAcceptorConnectorSink
	, public IRtObserver
{
public:
	CRtChannelHttpClient(CRtHttpUrl *aURL, CRtHttpProxyInfo *aPi = NULL);
	CRtChannelHttpClient(CRtHttpUrl *aURL, CRtChannelManager::CFlag aFlag);
	virtual ~CRtChannelHttpClient();

	// interface IRtReferenceControl
	virtual DWORD AddReference();
	virtual DWORD ReleaseReference();

	// interface IRtChannel
	virtual RtResult AsyncOpen(IRtChannelSink *aSink);

	virtual RtResult GetUrl(CRtHttpUrl *&aUrl);

	// interface IRtTransport
	virtual RtResult OpenWithSink(IRtTransportSink *aSink);
	virtual IRtTransportSink* GetSink();
	virtual RtResult SendData(
		CRtMessageBlock& inData,
		BOOL inSendImmediately = TRUE,
		BOOL inDestroyData = FALSE,
		DataPriority inPriority = DP_MEDIUM, 
		BOOL inNeedAck = TRUE);
	virtual RtResult SetOption(DWORD aCommand, LPVOID aArg);
	virtual RtResult GetOption(DWORD aCommand, LPVOID aArg);
	virtual RtResult Disconnect(RtResult aReason);

	// interface IRtChannelHttpClient
	virtual RtResult SetOrAddRequestHeader(
		const CRtString &aHeader, 
		const CRtString &aValue);

	virtual RtResult SetPath( const CRtString& aPath );

	virtual RtResult SetRequestMethod(const CRtString &aMethod);

	virtual RtResult GetRequestMethod(CRtString &aMethod);

	virtual RtResult GetResponseStatus(LONG &aStatus);

	virtual RtResult GetResponseHeader(
		const CRtString &aHeader, 
		CRtString &aValue);

	// interface IRtAcceptorConnectorSink
	virtual void OnConnectIndication(
		RtResult aReason,
		IRtTransport *aTrpt,
		IRtAcceptorConnectorId *aRequestId);

	// interface IRtTransportSink
	virtual void OnDisconnect(
		RtResult aReason,
		IRtTransport *aTrptId);

	// interface IRtObserver
	virtual void OnObserve(LPCSTR aTopic, LPVOID aData = NULL);

	// transfer transport, mainly used by CRtConnectorHttpProxyT.
	void TransferTransport(IRtTransport *&pTransport);
	
//	void OnResponseFinished();
	
protected:
	virtual RtResult ParserHttpProtocol_t(CRtMessageBlock &aData);
	virtual RtResult Close_t(RtResult aReason);

protected:
	RtResult Connect_i(const CRtInetAddr &aAddrPeer);
	RtResult ProcessAuthorization();
	RtResult AddAuthInfo(const CRtString &aChallenge);
	RtResult SetRequestMethod_i(const CRtHttpAtom &aMethod);
	BOOL IsTransportAlive();
	RtResult DoAuthorizationOpen_i();

protected:
	CRtAutoPtr<CRtHttpProxyInfo> m_pProxyInfo;
	CRtAutoPtr<CRtHttpUrl> m_pUrl;
	CRtAutoPtr<IRtConnector> m_pConnector;
	CRtHttpParserT<CRtHttpResponseHead, CRtChannelHttpClient> m_ParserResponse;
	IRtChannelSink *m_pChannelSink;

	CRtAutoPtr<IRtHttpAuthenticator> m_pHttpAuthenticator;
	DWORD m_dwAuthTimes;
	BOOL m_bIsAuthing;
	CRtChannelManager::CFlag m_FlagConnector;
	CRtString m_strFirstSend;

	// Store NTLM scheme for first auth by no need inputting username.
	CRtString m_strSchemeFirstBuffer;
	BOOL m_bNeedFirstNTLMAuth;
	BOOL m_bWWWAuth;
//	BOOL m_bFullResponse; 

	friend class CRtEventHttpClientAsyncOpen;
};

class CRtHttpProxyManager;

class /*RT_API_EXPORT*/ CRtChannelHttpClientWithBrowerProxy
	: public CRtChannelHttpClient
{
public:
	CRtChannelHttpClientWithBrowerProxy(
		CRtHttpUrl *aURL, 
		CRtChannelManager::CFlag aFlag);

	virtual ~CRtChannelHttpClientWithBrowerProxy();

	// interface IRtChannel
	virtual RtResult AsyncOpen(IRtChannelSink *aSink);

	// interface IRtAcceptorConnectorSink
	virtual void OnConnectIndication(
		RtResult aReason,
		IRtTransport *aTrpt,
		IRtAcceptorConnectorId *aRequestId);

	// interface IRtObserver
	virtual void OnObserve(LPCSTR aTopic, LPVOID aData = NULL);

protected:
	virtual RtResult Close_t(RtResult aReason);

private:
	CRtHttpProxyManager *m_pHttpProxyManager;
	IRtChannelSink *m_pSinkTemp;
	DWORD m_dwConnectCount;
	BOOL m_bOnConnectCalled;
};

class CRtEventHttpClientAsyncOpen: public IRtEvent
{
public:
	CRtEventHttpClientAsyncOpen(CRtChannelHttpClient* inHttpClient);
	virtual ~CRtEventHttpClientAsyncOpen();
	
	virtual RtResult OnEventFire();

protected:
	CRtAutoPtr<CRtChannelHttpClient> m_httpClient;
};


#endif // !RTCHANNELHTTPCLIENT_H
